﻿Imports System
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Windows.Forms

Namespace System.Workflow.ComponentModel.Design
    Friend NotInheritable Class ZoomingMessageFilter
        Inherits WorkflowDesignerMessageFilter
        ' Methods
        Friend Sub New(ByVal initiateZoomIn As Boolean)
            Me.currentState = Me.initialState = If(initiateZoomIn, ZoomState.In, ZoomState.Out)
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try 
                If (Not Me.fastZoomingMessageFilter Is Nothing) Then
                    RemoveHandler Me.fastZoomingMessageFilter.DragComplete, New EventHandler(AddressOf Me.OnZoomRectComplete)
                    MyBase.ParentView.RemoveDesignerMessageFilter(Me.fastZoomingMessageFilter)
                    Me.fastZoomingMessageFilter.Dispose
                    Me.fastZoomingMessageFilter = Nothing
                End If
                Me.RestoreUIState
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        Protected Overrides Sub Initialize(ByVal parentView As WorkflowView)
            MyBase.Initialize(parentView)
            Me.StoreUIState
            Me.RefreshUIState
        End Sub

        Protected Overrides Function OnDragEnter(ByVal eventArgs As DragEventArgs) As Boolean
            MyBase.ParentView.RemoveDesignerMessageFilter(Me)
            Return False
        End Function

        Protected Overrides Function OnKeyDown(ByVal eventArgs As KeyEventArgs) As Boolean
            If (eventArgs.KeyValue = &H1B) Then
                MyBase.ParentView.RemoveDesignerMessageFilter(Me)
            Else
                Me.currentState = If(((eventArgs.Modifiers And Keys.Shift) <> Keys.None), If((Me.initialState = ZoomState.In), ZoomState.Out, ZoomState.In), Me.initialState)
                Me.RefreshUIState
            End If
            Return True
        End Function

        Protected Overrides Function OnKeyUp(ByVal eventArgs As KeyEventArgs) As Boolean
            Me.currentState = If(((eventArgs.Modifiers And Keys.Shift) <> Keys.None), If((Me.initialState = ZoomState.In), ZoomState.Out, ZoomState.In), Me.initialState)
            Me.RefreshUIState
            Return True
        End Function

        Protected Overrides Function OnMouseCaptureChanged() As Boolean
            Return True
        End Function

        Protected Overrides Function OnMouseDoubleClick(ByVal eventArgs As MouseEventArgs) As Boolean
            Return True
        End Function

        Protected Overrides Function OnMouseDown(ByVal eventArgs As MouseEventArgs) As Boolean
            If (eventArgs.Button = MouseButtons.Left) Then
                Me.currentState = If(((Control.ModifierKeys And Keys.Shift) <> Keys.None), If((Me.initialState = ZoomState.In), ZoomState.Out, ZoomState.In), Me.initialState)
                Dim flag As Boolean = (Me.fastZoomingMessageFilter Is Nothing)
                Me.RefreshUIState
                If (flag AndAlso (Not Me.fastZoomingMessageFilter Is Nothing)) Then
                    DirectCast(Me.fastZoomingMessageFilter, IWorkflowDesignerMessageSink).OnMouseDown(eventArgs)
                End If
            End If
            Return True
        End Function

        Protected Overrides Function OnMouseEnter(ByVal eventArgs As MouseEventArgs) As Boolean
            Me.RefreshUIState
            Return True
        End Function

        Protected Overrides Function OnMouseLeave() As Boolean
            Return True
        End Function

        Protected Overrides Function OnMouseMove(ByVal eventArgs As MouseEventArgs) As Boolean
            Return True
        End Function

        Protected Overrides Function OnMouseUp(ByVal eventArgs As MouseEventArgs) As Boolean
            If ((eventArgs.Button = MouseButtons.Left) AndAlso Me.CanContinueZooming) Then
                Dim parentView As WorkflowView = MyBase.ParentView
                Dim zoomLevel As Integer = (parentView.Zoom + If((Me.currentState = ZoomState.In), ZoomingMessageFilter.ZoomIncrement, (-1 * ZoomingMessageFilter.ZoomIncrement)))
                Dim center As New Point(If((Me.currentState = ZoomState.In), eventArgs.X, (parentView.ViewPortSize.Width / 2)), If((Me.currentState = ZoomState.In), eventArgs.Y, (parentView.ViewPortSize.Height / 2)))
                Me.UpdateZoom(zoomLevel, center)
            End If
            Return True
        End Function

        Protected Overrides Function OnShowContextMenu(ByVal menuPoint As Point) As Boolean
            Dim service As IMenuCommandService = DirectCast(MyBase.GetService(GetType(IMenuCommandService)), IMenuCommandService)
            If (Not service Is Nothing) Then
                service.ShowContextMenu(WorkflowMenuCommands.ZoomMenu, menuPoint.X, menuPoint.Y)
                Me.RefreshUIState
            End If
            Return True
        End Function

        Private Sub OnZoomRectComplete(ByVal sender As Object, ByVal e As EventArgs)
            If ((Me.CanContinueZooming AndAlso (Me.currentState = ZoomState.In)) AndAlso ((Not Me.fastZoomingMessageFilter Is Nothing) AndAlso Not Me.fastZoomingMessageFilter.DragRectangle.IsEmpty)) Then
                Dim dragRectangle As Rectangle = Me.fastZoomingMessageFilter.DragRectangle
                Dim parentView As WorkflowView = MyBase.ParentView
                Dim center As Point = parentView.LogicalPointToClient(New Point((dragRectangle.Location.X + (dragRectangle.Width / 2)), (dragRectangle.Location.Y + (dragRectangle.Height / 2))))
                Dim zoomLevel As Integer = CInt((Math.Min(CSng((CSng(parentView.ViewPortSize.Width) / CSng(dragRectangle.Width))), CSng((CSng(parentView.ViewPortSize.Height) / CSng(dragRectangle.Height)))) * 100!))
                Me.UpdateZoom(zoomLevel, center)
            End If
        End Sub

        Private Sub RefreshUIState()
            Dim parentView As WorkflowView = MyBase.ParentView
            If Not Me.CanContinueZooming Then
                parentView.Cursor = ZoomingMessageFilter.ZoomDisabledCursor
            ElseIf (Me.currentState = ZoomState.In) Then
                parentView.Cursor = ZoomingMessageFilter.ZoomInCursor
            Else
                parentView.Cursor = ZoomingMessageFilter.ZoomOutCursor
            End If
            If (((Me.fastZoomingMessageFilter Is Nothing) AndAlso Me.CanContinueZooming) AndAlso (Me.currentState = ZoomState.In)) Then
                Me.fastZoomingMessageFilter = New DragRectangleMessageFilter
                AddHandler Me.fastZoomingMessageFilter.DragComplete, New EventHandler(AddressOf Me.OnZoomRectComplete)
                parentView.AddDesignerMessageFilter(Me.fastZoomingMessageFilter)
            ElseIf ((Not Me.fastZoomingMessageFilter Is Nothing) AndAlso (Not Me.CanContinueZooming OrElse (Me.currentState <> ZoomState.In))) Then
                RemoveHandler Me.fastZoomingMessageFilter.DragComplete, New EventHandler(AddressOf Me.OnZoomRectComplete)
                parentView.RemoveDesignerMessageFilter(Me.fastZoomingMessageFilter)
                Me.fastZoomingMessageFilter = Nothing
            End If
            Dim service As IMenuCommandService = [TryCast](MyBase.GetService(GetType(IMenuCommandService)),IMenuCommandService)
            If (Not service Is Nothing) Then
                Dim did As CommandID
                For Each did In CommandSet.NavigationToolCommandIds
                    Dim command As MenuCommand = service.FindCommand(did)
                    If ((Not command Is Nothing) AndAlso command.Enabled) Then
                        command.Checked = (command.CommandID Is If((Me.initialState = ZoomState.In), WorkflowMenuCommands.ZoomIn, WorkflowMenuCommands.ZoomOut))
                    End If
                Next
            End If
        End Sub

        Private Sub RestoreUIState()
            Dim service As IMenuCommandService = [TryCast](MyBase.GetService(GetType(IMenuCommandService)),IMenuCommandService)
            If (Not service Is Nothing) Then
                Dim did As CommandID
                For Each did In CommandSet.NavigationToolCommandIds
                    Dim command As MenuCommand = service.FindCommand(did)
                    If ((Not command Is Nothing) AndAlso command.Enabled) Then
                        command.Checked = (command.CommandID Is Me.previousCommand)
                    End If
                Next
            End If
            MyBase.ParentView.Cursor = Me.previousCursor
        End Sub

        Private Sub StoreUIState()
            Dim service As IMenuCommandService = [TryCast](MyBase.GetService(GetType(IMenuCommandService)),IMenuCommandService)
            If (Not service Is Nothing) Then
                Dim did As CommandID
                For Each did In CommandSet.NavigationToolCommandIds
                    Dim command As MenuCommand = service.FindCommand(did)
                    If (((Not command Is Nothing) AndAlso command.Enabled) AndAlso command.Checked) Then
                        Me.previousCommand = command.CommandID
                        Exit For
                    End If
                Next
            End If
            Me.previousCursor = MyBase.ParentView.Cursor
        End Sub

        Private Sub UpdateZoom(ByVal zoomLevel As Integer, ByVal center As Point)
            Dim empty As PointF = PointF.Empty
            Dim parentView As WorkflowView = MyBase.ParentView
            Dim point As Point = parentView.LogicalPointToClient(Point.Empty)
            center.X = (center.X - point.X)
            center.Y = (center.Y - point.Y)
            empty = New PointF((CSng(center.X) / CSng(parentView.HScrollBar.Maximum)), (CSng(center.Y) / CSng(parentView.VScrollBar.Maximum)))
            parentView.Zoom = Math.Min(Math.Max(zoomLevel, 10), 400)
            Dim point2 As New Point(CInt((parentView.HScrollBar.Maximum * empty.X)), CInt((parentView.VScrollBar.Maximum * empty.Y)))
            parentView.ScrollPosition = New Point((point2.X - (parentView.HScrollBar.LargeChange / 2)), (point2.Y - (parentView.VScrollBar.LargeChange / 2)))
            Me.currentState = If(((Control.ModifierKeys And Keys.Shift) <> Keys.None), If((Me.initialState = ZoomState.In), ZoomState.Out, ZoomState.In), Me.initialState)
            Me.RefreshUIState
        End Sub


        ' Properties
        Private ReadOnly Property CanContinueZooming As Boolean
            Get
                Dim parentView As WorkflowView = MyBase.ParentView
                Return (((Me.currentState = ZoomState.Out) AndAlso (parentView.Zoom > 10)) OrElse ((Me.currentState = ZoomState.In) AndAlso (parentView.Zoom < 400)))
            End Get
        End Property

        Friend ReadOnly Property ZoomingIn As Boolean
            Get
                Return (Me.initialState = ZoomState.In)
            End Get
        End Property


        ' Fields
        Private currentState As ZoomState
        Private fastZoomingMessageFilter As DragRectangleMessageFilter
        Private initialState As ZoomState
        Private previousCommand As CommandID
        Private previousCursor As Cursor = Cursors.Default
        Private Shared ZoomDisabledCursor As Cursor = New Cursor(GetType(WorkflowView), "Resources.zoomno.cur")
        Private Shared ZoomIncrement As Integer = 20
        Private Shared ZoomInCursor As Cursor = New Cursor(GetType(WorkflowView), "Resources.zoomin.cur")
        Private Shared ZoomOutCursor As Cursor = New Cursor(GetType(WorkflowView), "Resources.zoomout.cur")

        ' Nested Types
        Private Enum ZoomState
            ' Fields
            [In] = 0
            Out = 1
        End Enum
    End Class
End Namespace

